package manage.modules.menu.service.impl;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import manage.commons.utils.Pager;
import manage.commons.utils.TableNameUtil;
import manage.modules.BaseService;
import manage.modules.menu.model.Menu;
import manage.modules.menu.model.MenuFolders;
import manage.modules.menu.service.MenuService;
import manage.modules.rbac.model.ActionOfMenu;
import manage.modules.rbac.model.MenuOfRole;
import manage.modules.worker.model.WorkerOfRole;

import org.apache.commons.collections.CollectionUtils;
import org.apache.commons.lang3.StringUtils;
import org.springframework.jdbc.core.simple.ParameterizedBeanPropertyRowMapper;
import org.springframework.jdbc.core.simple.ParameterizedRowMapper;

public class MenuServiceImpl implements MenuService {
	private static final String MENU_TABLE_PRIMARY = "menuId";
	private static final String MENU_CACHE_KEY = "allMenu";
	private ParameterizedRowMapper<Menu> rowMapper = ParameterizedBeanPropertyRowMapper
			.newInstance(getClazz());
	private BaseService baseService;

	@Override
	public Menu select(Integer menuId) {
		return baseService.select(MENU_TABLE_PRIMARY, menuId, getClazz());
	}

	@Override
	public int insert(Menu menu) {
		int count = baseService.insert(menu);
		clearCacheByCount(count);
		return count;
	}

	@Override
	public int update(Menu menu) {
		int count = baseService.updateFields(MENU_TABLE_PRIMARY,
				menu.getMenuId(), menu);
		clearCacheByCount(count);
		return count;
	}

	@Override
	public int delete(Integer menuId) {
		int count = baseService.delete(MENU_TABLE_PRIMARY, menuId, getClazz());
		baseService.delete(MENU_TABLE_PRIMARY, menuId, MenuOfRole.class);
		baseService.delete(MENU_TABLE_PRIMARY, menuId, ActionOfMenu.class);
		clearCacheByCount(count);
		return count;
	}

	@Override
	public List<Menu> listAll() {
		List<Menu> allMenu = (List<Menu>) baseService.getListByCache(
				MENU_CACHE_KEY, getClazz());
		if (CollectionUtils.isEmpty(allMenu)) {
			allMenu = baseService.listAll(getClazz());
			if (CollectionUtils.isNotEmpty(allMenu)) {
				baseService.setCache(MENU_CACHE_KEY, allMenu);
			}
		}
		return allMenu;
	}

	@Override
	public boolean exists(Integer menuId) {
		return baseService.exists(MENU_TABLE_PRIMARY, menuId, getClazz());
	}

	@Override
	public boolean existChildMenu(Integer parentMenuId) {
		return baseService.exists("parentId", parentMenuId, getClazz());
	}

	@Override
	public Long getCountOfAll() {
		return baseService.countOfAll(getClazz());
	}

	@Override
	public List<Menu> listMenuByParentMenuId(Integer parentMenuId,
			int displayType) {
		Map<String, Object> fields = new HashMap<String, Object>();
		fields.put("display", displayType);
		fields.put("parentId", parentMenuId);
		return baseService.listByFields(fields, getClazz());
	}

	@Override
	public List<Menu> listChildMenuByWorkerIdAndParentId(Long workerId,
			Integer parentMenuId) {
		String querySql = "select * from "
				+ TableNameUtil.getTableName(MenuOfRole.class) + " mor "
				+ " join " + TableNameUtil.getTableName(WorkerOfRole.class)
				+ " wor on  wor.roleId=mor.roleId" + " join "
				+ TableNameUtil.getTableName(getClazz())
				+ " m on mor.menuId=m.menuId"
				+ " where m.parentId=? and wor.workerId=?";
		return baseService.getJdbcOperations().query(querySql, rowMapper,
				parentMenuId, workerId);
	}

	@Override
	public List<Menu> listVisableMenuByParentMenuId(Integer parentMenuId) {
		return listMenuByParentMenuId(parentMenuId, 1);
	}

	@Override
	public List<Menu> listHideMenuByParentMenuId(Integer parentMenuId) {
		return listMenuByParentMenuId(parentMenuId, 0);
	}

	@Override
	public List<Menu> listAllParentMenu() {
		return baseService.listByField("parentId", 0, getClazz());
	}

	@Override
	public void query(Menu menu, Pager<Menu> pager) {
		StringBuilder querySql = new StringBuilder(1024);
		querySql.append("select * from "
				+ TableNameUtil.getTableName(getClazz()) + " where 1=1");
		if (menu != null) {
			if (StringUtils.isNotBlank(menu.getMenuName())) {
				querySql.append(" and menuName like '%" + menu.getMenuName()
						+ "%'");
			}
			if (StringUtils.isNotBlank(menu.getUrl())) {
				querySql.append(" and url =" + menu.getUrl());
			}
			if (null != menu.getParentId()) {
				querySql.append(" and parentId =" + menu.getParentId());
			}
			if (null != menu.getOrderNo()) {
				querySql.append(" and orderNo =" + menu.getOrderNo());
			}
			if (null != menu.getDisplay()) {
				querySql.append(" and display =" + menu.getDisplay());
			}
			pager.setRowCount(baseService.getJdbcOperations().queryForLong(
					baseService.getCountSql(querySql.toString())));
			querySql.append(" limit ?,?");
			pager.setList(baseService.getJdbcOperations().query(
					querySql.toString(), rowMapper, pager.getRowOffset(),
					pager.getPageSize()));
		}

	}

	@Override
	public List<Menu> listParentMenuByWorkerId(Long workerId) {
		String sql = "select m.* from "
				+ TableNameUtil.getTableName(WorkerOfRole.class)
				+ " wor join "
				+ TableNameUtil.getTableName(MenuOfRole.class)
				+ " mor on wor.roleId=mor.roleId"
				+ " join "
				+ TableNameUtil.getTableName(getClazz())
				+ " m on mor.menuId=m.menuId where wor.workerId=? and m.parentId=0 order by m.orderNo";
		return baseService.getJdbcOperations().query(sql, rowMapper, workerId);
	}

	@Override
	public List<MenuFolders> listMenusByWorkerId(Long workerId) {
		List<Menu> menus = listParentMenuByWorkerId(workerId);
		List<MenuFolders> menuFolders = new ArrayList<MenuFolders>();
		for (Menu menu : menus) {
			List<Menu> childMenus = listChildMenuByWorkerIdAndParentId(
					workerId, menu.getMenuId());
			MenuFolders menuFolder = new MenuFolders(menu, childMenus);
			menuFolders.add(menuFolder);
		}
		return menuFolders;
	}

	@Override
	public List<MenuFolders> listMenuByRoleId(Integer roleId) {
		List<MenuFolders> folders = new ArrayList<MenuFolders>();
		String sql = "select m.* from "
				+ TableNameUtil.getTableName(MenuOfRole.class) + " mr join "
				+ TableNameUtil.getTableName(getClazz())
				+ " m on m.menuId=mr.menuId"
				+ " where m.parentId=0 and mr.roleId=? and display=1";
		List<Menu> rootMenus = baseService.getJdbcOperations().query(sql,
				rowMapper, roleId);
		List<Menu> allSubMenu = listChildMenuByRoleId(roleId);
		for (Menu rootMenu : rootMenus) {
			List<Menu> menus = new ArrayList<Menu>();
			for (Menu m : allSubMenu) {
				if (m.getParentId() == rootMenu.getMenuId()) {
					menus.add(m);
				}
			}
			folders.add(new MenuFolders(rootMenu, menus));
		}
		return folders;
	}

	@Override
	public List<MenuFolders> listMenuFolders() {
		List<MenuFolders> folders = new ArrayList<MenuFolders>();
		List<Menu> rootMenus = listAllParentMenu();
		for (Menu rootMenu : rootMenus) {
			folders.add(listMenuAndChilds(rootMenu.getMenuId()));
		}
		return folders;
	}

	@Override
	public List<Menu> listChildMenuByRoleId(Integer roleId) {
		String subSql = "select m.* from "
				+ TableNameUtil.getTableName(MenuOfRole.class) + " mr join "
				+ TableNameUtil.getTableName(getClazz())
				+ " m on m.menuId=mr.menuId"
				+ " where m.parentId>0 and mr.roleId=? and display=1";
		return baseService.getJdbcOperations().query(subSql, rowMapper, roleId);
	}

	@Override
	public MenuFolders listMenuAndChilds(Integer menuId) {
		Menu menu = select(menuId);
		List<Menu> chlidMenus = listVisableMenuByParentMenuId(menuId);
		return new MenuFolders(menu, chlidMenus);
	}

	private void clearCacheByCount(int count) {
		if (count > 0) {
			baseService.clearCache(MENU_CACHE_KEY);
		}
	}

	public Class<Menu> getClazz() {
		return Menu.class;
	}

	public void setBaseService(BaseService baseService) {
		this.baseService = baseService;
	}

}
